package kibahed.uni.mdp.visualisation;


import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import kibahed.uni.mdp.calculation.IFMDPAlgorithm;
import kibahed.uni.mdp.calculation.MDP_Data;
import kibahed.uni.mdp.calculation.OptimalPolicy;
import kibahed.uni.mdp.calculation.QLearning;

public class KBMdpArea extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public static void main(String[] args) {
		KBMdpArea area = new KBMdpArea();
	}

	private int amountOfRows = 5;
	private int amountOfCollumns = 5;
	private double discountFactor = 0.9;
	private int startField = 0;

	KBLocalPanel[][] mainPanelMap = new KBLocalPanel[amountOfRows][amountOfCollumns];
	JFrame frame = new JFrame();
	JScrollPane scrollPane = new JScrollPane();
	int[] testResults = { 2, 1, 1, 2, 3, 2, 1, 4, 3, 1, 1, 1, 4, 5, 4, 3, 3, 3,
			4, 4, 1, 1, 2, 2, 2 };
	double[] rewards = new double[mainPanelMap.length * mainPanelMap[0].length];
	double[] noises = new double[mainPanelMap.length * mainPanelMap[0].length];

	
	JPanel headerPanel = new JPanel();
	JPanel mainPanel = new JPanel();
	JPanel footPanel = new JPanel();

	JRadioButton[] radioButtons = new JRadioButton[mainPanelMap.length
			* mainPanelMap[0].length];
	ButtonGroup buttonGroup = new ButtonGroup();

	public KBMdpArea() {
		this.setLayout(new BorderLayout());
		prepareHeaderPanel();
		prepareMainPanel();
		prepareFootPanel();
		fillRadioButtons();
		prepareMainPanels();
		fillHeader();
		fillFootPanel();
		fillThisPanel();
		setDefaultValues();
		openWindow();
	}

	private void setDefaultValues() {
		mainPanelMap[0][1].setReward(-1);
		mainPanelMap[0][3].setReward(-1);
		mainPanelMap[2][1].setReward(-1);
		mainPanelMap[2][3].setReward(-1);
		
		mainPanelMap[2][4].setReward(1);
		
		mainPanelMap[1][1].setNoise(1);
		mainPanelMap[1][2].setNoise(1);
		mainPanelMap[1][3].setNoise(1);
		mainPanelMap[2][2].setNoise(1);
		
	}

	private void fillRadioButtons() {
		for (int i = 0; i < radioButtons.length; i++) {
			final JRadioButton b = new JRadioButton();
			radioButtons[i] = b;
			final int value = i;
			ActionListener al = new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent e) {
					if (b.isSelected()) {
						startField = value;
					}
				}
			};
			buttonGroup.add(b);
		}
	}

	private void fillFootPanel() {
		JButton oButton = new JButton("start optimal policy");
		JButton qButton = new JButton("start q learning");
		footPanel.add(oButton);
		footPanel.add(qButton);
		ActionListener al = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				MDP_Data data = new MDP_Data(getAmountOfRows(),
						getAmountOfCollumns(), getDiscountFactor(),
						getNoises(), getRewards(),true);
				IFMDPAlgorithm alg = new OptimalPolicy(data);
				alg.calculate();
				displayResults(alg.getEvaluatedPolicy());
				setValues(alg.getEvaluatedValues());
			}
		};
		ActionListener al2 = new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				try {
					int iterations = Integer.parseInt(JOptionPane
							.showInputDialog(null, "Iterations"));
					double epsilon = Double.parseDouble(JOptionPane
							.showInputDialog(null, "Epsilon"));
					MDP_Data data = new MDP_Data(getAmountOfRows(),
							getAmountOfCollumns(), getDiscountFactor(),
							getNoises(), getRewards(),true);
					IFMDPAlgorithm alg = new QLearning(data, epsilon,
							iterations, startField);
					alg.calculate();
					displayResults(alg.getEvaluatedPolicy());
					setValues(alg.getEvaluatedValues());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		qButton.addActionListener(al2);
		oButton.addActionListener(al);
	}

	private void prepareFootPanel() {
		footPanel.setLayout(new FlowLayout());

	}

	private void fillHeader() {
		JLabel descLabel = new JLabel("discount factor:");
		final JTextField descField = new JTextField(5);
		descField.setText("" + discountFactor);
		KeyListener listener = new KeyListener() {

			@Override
			public void keyTyped(KeyEvent arg0) {
				try {
					discountFactor = Double.parseDouble(descField.getText());
				} catch (Exception e) {
					e.printStackTrace();
				}

			}

			@Override
			public void keyReleased(KeyEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyPressed(KeyEvent arg0) {
				// TODO Auto-generated method stub

			}
		};
		descField.addKeyListener(listener);
		headerPanel.add(descLabel);
		headerPanel.add(descField);

	}

	private void prepareMainPanel() {
		mainPanel.setLayout(new BorderLayout());

	}

	private void prepareHeaderPanel() {
		headerPanel.setLayout(new FlowLayout());

	}

	private void fillThisPanel() {

		this.add(headerPanel, BorderLayout.NORTH);
		this.add(mainPanel, BorderLayout.CENTER);
		this.add(footPanel, BorderLayout.SOUTH);
		mainPanel.setLayout(new GridLayout(mainPanelMap.length,
				mainPanelMap[0].length));
		for (int i = 0; i < mainPanelMap.length; i++) {
			for (int j = 0; j < mainPanelMap[0].length; j++) {
				mainPanel.add(mainPanelMap[i][j]);
			}
		}
	}

	private void prepareMainPanels() {

		for (int i = 0; i < mainPanelMap.length; i++) {
			for (int j = 0; j < mainPanelMap[0].length; j++) {
				KBLocalPanel panel = new KBLocalPanel(radioButtons[i
						* mainPanelMap.length + j]);
				mainPanelMap[i][j] = panel;
			}
		}
	}

	private void openWindow() {
		frame.add(scrollPane);
		scrollPane.setViewportView(this);
		frame.pack();
		frame.setVisible(true);
	}

	public void displayResults(int[] results) {
		if (results.length == mainPanelMap.length * mainPanelMap[0].length) {
			for (int i = 0; i < mainPanelMap.length; i++) {
				for (int j = 0; j < mainPanelMap[0].length; j++) {
					KBLocalPanel panel = mainPanelMap[i][j];
					panel.setNextAction(results[i * mainPanelMap.length + j] + 1);
				}
			}

			this.validate();
		}
	}

	public double[] getRewards() {
		for (int i = 0; i < mainPanelMap.length; i++) {
			for (int j = 0; j < mainPanelMap[0].length; j++) {
				KBLocalPanel panel = mainPanelMap[i][j];
				rewards[i * mainPanelMap.length + j] = panel.getReward();
			}
		}

		return rewards;
	}

	public double[] getNoises() {
		for (int i = 0; i < mainPanelMap.length; i++) {
			for (int j = 0; j < mainPanelMap[0].length; j++) {
				KBLocalPanel panel = mainPanelMap[i][j];
				noises[i * mainPanelMap.length + j] = panel.getNoise();
			}
		}
		
		return noises;
	}

	public int getAmountOfRows() {
		return amountOfRows;
	}

	public void setAmountOfRows(int amountOfRows) {
		this.amountOfRows = amountOfRows;
	}

	public int getAmountOfCollumns() {
		return amountOfCollumns;
	}

	public void setAmountOfCollumns(int amountOfCollumns) {
		this.amountOfCollumns = amountOfCollumns;
	}

	public double getDiscountFactor() {
		return discountFactor;
	}

	public void setDiscountFactor(double discountFactor) {
		this.discountFactor = discountFactor;
	}
	
	public void setValues(double[] values){
		if(values.length==mainPanelMap.length*mainPanelMap[0].length){
			for (int i = 0; i < mainPanelMap.length; i++) {
				for (int j = 0; j < mainPanelMap[0].length; j++) {
					KBLocalPanel panel = mainPanelMap[i][j];
					panel.setValue(Math.round(values[i * mainPanelMap.length + j]*10000)/10000.);
				}
			}
		}
	}

}
